<?php
/**
 *  Helps to extract test cases automatically from a file.
 */
class QStone_FileLoader{
    private static $loader = null;
    private function __construct(){}
    private function __clone(){}
    public static function getLoader(){
        if(!self::$loader instanceof self){
            self::$loader = new self();
        }
        return self::$loader;
    }

    function load($title,$files){
        $existing_classes = get_declared_classes();
        $existing_globals = get_defined_vars();
        if(is_array($files)){
            foreach($files as $test_file){
                include_once ( $test_file );
            }
        }
        else{
            include_once($files);
        }
        $new_globals = get_defined_vars();
        $this->makeFileVariablesGlobal($existing_globals, $new_globals);
        $new_classes = array_diff(get_declared_classes(),$existing_classes);
        if(!empty($new_classes)){
            $classes = $this->selectRunnableTests($new_classes);
               return $this->createSuiteFromClasses($title, $classes);
        }
        return null;
    }

    /**
     *    Imports new variables into the global namespace.
     *    @param hash $existing   Variables before the file was loaded.
     *    @param hash $new        Variables after the file was loaded.
     *    @access private
     */
    protected function makeFileVariablesGlobal($existing, $new) {
        $globals = array_diff(array_keys($new), array_keys($existing));
        foreach ($globals as $global) {
            $GLOBALS[$global] = $new[$global];
        }
    }

    /**
     *    @param array $candidates   Candidate classes.
     *    @return array              New classes which are test
     *    @access public
     */
    function selectRunnableTests($candidates) {
        $classes = array();
        foreach ($candidates as $class) {
            if (QStone_Context::isTest($class)) {
                $classes[] = $class;
            }
        }
        return $classes;
    }

    /**
     *    Builds a test suite from a class list.
     *    @param string $title       Title of new group.
     *    @param array $classes      Test classes.
     *    @return TestSuite          Group loaded with the new
     *                               test cases.
     *    @access public
     */
    function createSuiteFromClasses($title, $classes) {
        if (count($classes) == 0) {
            $suite = new Test_Suite_Bad($title, "No runnable test cases in [$title]");
            return $suite;
        }
        $suite = new Test_Suite($title);
        foreach ($classes as $class) {
            $suite->add($class);
        }
        return $suite;
    }
}
?>
